home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / msysjour / vol04 / 03 / vmm / vm.c next >
C/C++ Source or Header  |  1989-01-10  |  20KB  |  809 lines

  1. /*******************************************************************/
  2. /* Virtual Memory Manager          VM.C                            */
  3. /*                                                                 */
  4. /* (C) Copyright 1988 Marc Adler/Magma Systems-All Rights Reserved */
  5. /*                                                                 */
  6. /* This software is for personal use only, and may not be used in  */
  7. /* any commercial product, nor may it sold in any way.             */
  8. /*                                                                 */
  9. /*******************************************************************/
  10.  
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <dos.h>
  14. #include <malloc.h>
  15. #include <fcntl.h>
  16. #include <io.h>
  17. #include <sys\types.h>
  18. #include <sys\stat.h>
  19. #include "vm.h"
  20.  
  21.  
  22. /* macro to return a ptr to a freeinfo structure */
  23. #define FREEPTR(pg, offset)   (FREEINFO *) (pg->memaddr + offset)
  24.  
  25. unsigned TotalPages = 0;     /* Total # of pages allocated */
  26. char VMInitialized = NO;     /* TRUE if the VMM has be initialized */
  27. PAGE *PageList = NULL;       /* Linked list of pages */
  28. VMFILE VMFile;               /* VM File info */
  29. unsigned VMPageSize = PAGESIZE; /* Pagesize of a VM block */
  30. unsigned long LRUclock = 0;     /* Clock used for LRU swapping */
  31. unsigned Emergency = NO;        /* TRUE if DOS has no more memory */
  32.  
  33.  
  34.  
  35. /* VMInit
  36.      Initialize the Virtual Memory Manager (VMM).
  37. */
  38. VMInit()
  39. {
  40.   char *mktemp();
  41.   char *pascal strend();
  42.   int  i;
  43.   char *tempdir;
  44.   
  45.   /* 
  46.      Create the VM swap file. Try to use the path specified in the
  47.      METEMP environment variable. If METEMP was not specified, use
  48.      the current directory.
  49.   */
  50.   VMFile.filename[0] = '\0';
  51.   if ((tempdir = getenv("METEMP")) != NULL)
  52.   {
  53.     char *end = strend(strcpy(VMFile.filename, tempdir));
  54.     if (end[-1] != '\\')                    /* add the backslash */
  55.     {
  56.       *end = '\\';
  57.       *++end = '\0';
  58.     }
  59.   }
  60.  
  61.   strcat(VMFile.filename, mktemp("VMXXXXXX"));
  62.   if ((VMFile.fd = open(VMFile.filename, 
  63.                          O_RDWR|O_TRUNC|O_CREAT|O_BINARY,
  64.                          S_IWRITE|S_IREAD)) < 0)
  65.   {
  66.     err("VMM - Cannot initialize VM system");
  67.     die(-1);
  68.   }
  69.   
  70.   for (i = 0;  i < MAXSLOTS;  i++)
  71.     VMFile.slottable[i].page = NULL;
  72.  
  73.   VMInitialized = YES;
  74.   return 0;
  75. }
  76.  
  77.  
  78. /* VMTerminate
  79.      Close and delete the VM swap file.
  80. */
  81. VMTerminate()
  82. {
  83.   if (VMInitialized)
  84.   {
  85.     close(VMFile.fd);
  86.     unlink(VMFile.filename);
  87.     VMInitialized = NO;
  88.   } 
  89. }
  90.  
  91.  
  92. /* MemDeref
  93.      main routine for dereferencing a VM handle.
  94. */
  95. char far *MemDeref(h)
  96.   HANDLE h;
  97. {
  98.   int  pid, offset;
  99.   PAGE *p, *prevp;
  100.  
  101.   /* Separate the handle into the page id 
  102.      and the offset within that page */ 
  103.  
  104.   pid = (int) ((h >> 16) & 0x0000FFFF);
  105.   offset = (int) (h & 0x0000FFFF);
  106.   
  107.   /* Search the linked list of pages for 
  108.      the page with id 'pid'. */ 
  109.  
  110.   for (prevp=p=PageList; p && p->id != pid; prevp=p, p=p->next)
  111.     ;
  112.  
  113.   if (!p)
  114.     return (HANDLE) NULL;
  115.     
  116.   /* If the page is not in conventional memory, swap it in. */
  117.   if (!(p->flags & PAGE_IN_MEM))
  118.     SwapinPage(p);
  119.  
  120.   /* Update the LRU count and bring the 
  121.      page to the front of the pagelist */
  122.  
  123.   p->LRUcount = LRUclock++;
  124.   if (p != PageList)
  125.   {
  126.     prevp->next = p->next;
  127.     p->next = PageList;
  128.     PageList = p;
  129.   }
  130.  
  131.   /* Return the absolute address which the handle references. */
  132.   return p->memaddr + offset;
  133. }
  134.  
  135.  
  136. MakePageDirty(h)
  137.   HANDLE h;
  138. {
  139.   PAGE *p;
  140.   if ((p = PageDeref(h)) != NULL)
  141.     SET_PAGE_DIRTY(p);
  142. }
  143.  
  144.  
  145. PAGE *PageDeref(h)
  146.   HANDLE h;
  147. {
  148.   int  pid, offset;
  149.   PAGE *p;
  150.  
  151.   /* Separate the handle into the page id 
  152.      and the offset within that page */ 
  153.  
  154.   pid = (int) ((h >> 16) & 0x0000FFFF);
  155.   offset = (int) (h & 0x0000FFFF);
  156.   
  157.   /* Search the linked list of pages for the page with id 'pid'. */
  158.   for (p = PageList;  p && p->id != pid;  p = p->next)
  159.     ;
  160.   return p;
  161. }
  162.  
  163.  
  164. /* AllocPage
  165.      Allocates a new page and links it to the page list.
  166. */
  167. PAGE *AllocPage()
  168. {
  169.   PAGE *p;
  170.   char *s;
  171.   FREEINFO *f;
  172.   
  173.   /* Make sure that the VMM is ready. */
  174.   if (!VMInitialized)
  175.     VMInit();
  176.  
  177.   /* Allocate the page structure from the heap */
  178.   if ((p = (PAGE *) calloc(sizeof(PAGE), 1)) == NULL)
  179.     return NULL;
  180.     
  181.   /* Allocate the page's text buffer from DOS or EMM */
  182.   if ((s = AllocPageText(p, VMPageSize)) == NULL)
  183.     return NULL;
  184.  
  185.   /* Fill the page structure. */ 
  186.   p->memaddr       = s;
  187.   p->flags        |= PAGE_IN_MEM;
  188.   p->id            = ++TotalPages;
  189.   p->LRUcount      = LRUclock++;
  190.   p->pagesize      = VMPageSize;
  191.   p->freebyte      = 0;
  192.   p->bytesfree     = VMPageSize;
  193.   p->maxcontigfree = VMPageSize;
  194.  
  195.   /*
  196.      Set up the page's initial free node. 
  197.  
  198.         p                  memaddr
  199.     ----------------     ---------------
  200.     | freebyte | 0 |---> |nextfree |-1 |
  201.     ----------------     ---------------
  202.     | bytesfree|4K |     |bytesfree|4K |
  203.     ----------------     ---------------
  204.   */
  205.  
  206.  f = (FREEINFO *) s;
  207.   f->bytesfree = VMPageSize;
  208.   f->nextfree  = FREELIST_END;
  209.  
  210.   /* Link the page to the head of the pagelist. */ 
  211.   p->next = PageList;
  212.   PageList = p;
  213.  
  214.   return p;
  215. }
  216.  
  217.  
  218. /* AllocPageText
  219.  * Allocs a block of 'size' bytes to be used as the page's buffer.
  220.  */
  221.  
  222. char far *AllocPageText(page, size)
  223.   PAGE     *page;
  224.   unsigned size;
  225. {
  226.   PAGE *p;
  227.   char far *s;
  228.  
  229.   /* Use DOSALLOC() to allocate the 4K page buffer */
  230.   while ((s = mymalloc(size)) == NULL /* || test_swap */)
  231.   {
  232.     /* Swap out the Least Recently Used page. 
  233.        Return the LRU page ptr. */
  234.  
  235.     if ((p = FindLRUPage()) == NULL)
  236.     {
  237.       err("VMM - FindLRUPage() can't find a page to swap"); 
  238.       return NULL;
  239.     }
  240.  
  241.     /* Use the swapped-out page's text buffer as the new buffer. */
  242.     s = p->memaddr;
  243.     SwapoutPage(p, NO);
  244.     memset(s, 0, size);
  245.     break;
  246.   }
  247.  
  248.   return s;
  249. }
  250.  
  251.  
  252. /*
  253.   ReadPage()
  254.   This is called from MemDeref() when the referenced page is not in
  255.   conventional memory.
  256.   
  257.   If the page is already in memory, then just return;
  258.   
  259.   Seek to the disk address and read the proper number of bytes
  260.   mark the page as being in memory
  261.  
  262. */
  263.  
  264. ReadPage(p)
  265.   PAGE *p;
  266. {
  267.   char *s;
  268.  
  269.   if (p->flags & PAGE_ON_DISK)
  270.   {
  271.     /* Obtain a text buffer which the 
  272.        swapped page will be read into. */
  273.  
  274.     if ((s = AllocPageText(p, p->pagesize)) == NULL)
  275.       return -1;
  276.  
  277.     /* Seek to the proper place and read the page. */
  278.     lseek(VMFile.fd, (long) (p->pagesize * p->diskaddr), 0);
  279.     if (read(VMFile.fd, p->memaddr = s, p->pagesize) != p->pagesize)
  280.     {
  281.       err("FATAL ERROR! read() failed in ReadPage()");
  282.       die(-1);
  283.     }
  284.  
  285.     /* Say that the page is now in conventional 
  286.        memory as well as on disk. */
  287.  
  288.     p->flags |= PAGE_IN_MEM;
  289.     p->LRUcount = LRUclock++;
  290.   }
  291.  
  292.   return 0;
  293. }
  294.  
  295.  
  296. /*
  297.   WritePage()
  298.   
  299.   If the page is on disk or it's in memory and there 
  300.   is a copy out on disk and the page isn't dirty return
  301.     
  302.   Find a free sector in the VM file
  303.   Seek to the free sector and write the page
  304.   Clear the dirty bit
  305.   make an entry in the page/disk table and put the page in there
  306. */
  307.  
  308. WritePage(p)
  309.   PAGE *p;
  310. {
  311.   unsigned sector;
  312.  
  313.   /* If the page is not in memory, then don't write it to disk */
  314.   if (!(p->flags & PAGE_IN_MEM))
  315.     return 0;
  316.     
  317.   /* The page has a disk sector allocated to it already */
  318.   if ((p->flags & PAGE_ON_DISK) && !(p->flags & IS_DIRTY))
  319.     return 0;  /* the in-mem copy is the same as the copy on disk */
  320.   
  321.   if ((sector = FindSlotFree()) == 0xFFFF)
  322.   {
  323.     err("VMM - No more slots free.");
  324.     return -1;
  325.   }
  326.  
  327.   /* See to the sector and dump the page text. */ 
  328.   lseek(VMFile.fd, (long) (sector * (long) p->pagesize), 0);
  329.   if (write(VMFile.fd, p->memaddr, p->pagesize) != p->pagesize)
  330.   {
  331.     err("FATAL ERROR! write() failed in WritePage()");
  332.     exit(-1);
  333.   }
  334.   
  335.   VMFile.slottable[sector].page = p;
  336.   p->diskaddr = (long) sector;
  337.   p->flags |= PAGE_ON_DISK;
  338.   p->flags &= ~IS_DIRTY;
  339.   p->LRUcount = LRUclock++;
  340. }
  341.  
  342.  
  343. SwapOutAllPages()
  344. {
  345.   PAGE *p;
  346.   for (p = PageList;  p;  p = p->next)
  347.     SwapoutPage(p, YES);
  348. }
  349.  
  350.  
  351. /*
  352.   This is called from AllocPageText() when there 
  353.   is no more DOS memory free and no more Expanded 
  354.   memory free to allocate a page.
  355. */
  356.  
  357. SwapoutPage(p, free_it)
  358.   PAGE *p;
  359. {
  360.   WritePage(p);
  361.   if (free_it)
  362.   {
  363.     if (p->flags & PAGE_IN_MEM)
  364.       my_free(p->memaddr);
  365.   }
  366.   p->flags &= ~PAGE_IN_MEM;
  367. }
  368.  
  369.  
  370. SwapInAllPages()
  371. {
  372.   PAGE *p;
  373.   for (p = PageList;  p;  p = p->next)
  374.     SwapinPage(p);
  375. }
  376.  
  377. SwapinPage(p)
  378.   PAGE *p;
  379. {
  380.   ReadPage(p);
  381. }
  382.  
  383.  
  384. /*
  385.    FindLRUPage 
  386.    Finds the Least Recently Used page and returns a pointer to it.
  387. */
  388.  
  389. PAGE *FindLRUPage()
  390. {
  391.   PAGE *p;
  392.   PAGE *retp = NULL;
  393.   unsigned long minLRU = 0xFFFFFFFF;
  394.   
  395.   for (p = PageList;  p;  p = p->next)
  396.   {
  397.     if ((p->flags & PAGE_IN_MEM) && 
  398.          p->LRUcount <= minLRU)       /* && IS_SWAPPABLE */
  399.     {
  400.       retp = p;
  401.       minLRU = p->LRUcount;
  402.     }
  403.   }
  404.   
  405.   return retp;
  406. }
  407.  
  408.  
  409. /* 
  410.   FindSlotFree
  411.      returns the first unused entry in VMFile.slottable
  412. */
  413. FindSlotFree()
  414. {
  415.   register int i;
  416.   
  417.   for (i = 0;  i < MAXSLOTS;  i++)
  418.     if (VMFile.slottable[i].page == NULL)
  419.       return i;
  420.   return -1;
  421. }
  422.  
  423.  
  424. /**********************************************************/
  425. /*                                                        */
  426. /*         Routines to allocate mem from a page           */
  427. /*                                                        */
  428. /**********************************************************/
  429.  
  430. /*
  431.   MyAlloc(n)
  432.   
  433.   We want to allocate n bytes from the system.
  434.   
  435.   Make sure that n is less than VMPageSize.
  436.   Make sure that n is a mutiple of 8.
  437.  
  438.   Find a page which has a contiguous block of n 
  439.   bytes free. Give preference to a page which is 
  440.   already in memory.
  441.   
  442.   If a page has n bytes free but not contiguous, 
  443.   then we will do compaction on the page.
  444.  
  445.   If there is still no page with n bytes free, 
  446.   then allocate a new page.
  447.   
  448.   At this point, we have a page 'p' with at least 
  449.   n bytes free.
  450.   
  451.   Decrease the bytes-free count of the page.
  452.   Link the unallocated bytes onto the page's free list.
  453.   Update the MaxContiguousFree count of the page.
  454.  
  455.   Return the Page/Offset value to the caller.
  456. */
  457.  
  458. HANDLE MyAlloc(needed)
  459.   unsigned needed;
  460. {
  461.   FREEINFO *f, *prevf, *newf;
  462.   PAGE     *p, *FindNBytesFree();
  463.   unsigned offset, bytes_needed, bytes_left;
  464.   unsigned maxcontig, new_offset;
  465.   HANDLE h;
  466.  
  467.   needed = (needed + sizeof(FREEINFO));
  468.   if (needed <= 0 || needed > VMPageSize)
  469.   {
  470.     return (HANDLE) NULL;
  471.   }
  472.  
  473.   /* Return a page that has at least 'needed' bytes free */
  474.   if ((p = FindNContigBytesFree(needed)) == NULL)
  475.     return (HANDLE) NULL; 
  476.  
  477.   /* Traverse the list of free chunks in 
  478.      the page and find the first  */
  479.  
  480.   /* chunk with 'needed' bytes free. 'F' 
  481.      will be the addr of the chunk. */
  482.  
  483.   maxcontig = 0;
  484.   offset = p->freebyte;
  485.  
  486.   for (f = (FREEINFO *) (p->memaddr + p->freebyte);  
  487.            f->bytesfree < needed;
  488.            f = (FREEINFO *) (p->memaddr + offset))
  489.   {
  490.     prevf = f;   /* save ptr to previous chunk for linking */
  491.     if ((offset = f->nextfree) == FREELIST_END)
  492.  
  493.       /* If we get here, then there is not 'needed' 
  494.          contiguous bytes free */
  495.  
  496.       return (HANDLE) NULL; 
  497.     maxcontig = max(maxcontig, f->bytesfree);
  498.   }
  499.       
  500.   /* Unlink and relink f (make sure there 
  501.      is enough room for the link) */
  502.  
  503.   bytes_left = f->bytesfree - needed;
  504.   if (bytes_left <= sizeof(FREEINFO))  /* less than 4 
  505.                                           bytes remaining? */
  506.   {
  507.     needed = f->bytesfree;  /* no room for the link - */
  508.     bytes_left = 0;         /* alloc the whole thing  */
  509.   }
  510.  
  511.   /* 
  512.      If the chunk that we are allocating is smaller than the 
  513.      page's biggest free chunk, then there should be no change 
  514.      to the max. We set maxcontig equal to the page's maxcontig 
  515.      so that we won't traverse the rest of the free chain below.
  516.    */
  517.  
  518.   if (f->bytesfree < p->maxcontigfree)
  519.     maxcontig = p->maxcontigfree;
  520.  
  521.   if (bytes_left == 0)
  522.   { /* We allocate the entire chunk */
  523.     if (offset == p->freebyte)   /* The chunk is the 1st free one */
  524.       p->freebyte = f->nextfree; /* so, relink the head pointer.  */
  525.     else
  526.       prevf->nextfree = f->nextfree;    /* Relink the previous */
  527.     new_offset = f->nextfree;           /* chunk to next       */
  528.   }
  529.  
  530.   else /* if (bytes_left) */
  531.   { /* There is some space left over in the chunk */
  532.     if (offset == p->freebyte)
  533.       p->freebyte = offset + needed;
  534.     else
  535.       prevf->nextfree = offset + needed;
  536.     /* Create a new chunk from the remaining bytes */
  537.     newf = (FREEINFO *) (p->memaddr + offset + needed);
  538.     newf->nextfree = f->nextfree;
  539.     newf->bytesfree = bytes_left;
  540.     maxcontig = max(maxcontig, newf->bytesfree);
  541.     new_offset = offset + needed;
  542.   }
  543.  
  544.   /* Now we traverse the rest of the freelist looking for a chunk */
  545.   /* with more bytes free than maxcontig.                         */
  546.   if (maxcontig < p->maxcontigfree && new_offset != FREELIST_END)
  547.   {
  548.     FREEINFO *f2;
  549.     for (f2 = (FREEINFO *) (p->memaddr + new_offset);
  550.          f2->bytesfree < p->maxcontigfree;
  551.          f2 = (FREEINFO *) (p->memaddr + new_offset))
  552.     if ((new_offset = f2->nextfree) == FREELIST_END)
  553.       break;
  554.     maxcontig = max(maxcontig, f2->bytesfree);
  555.   }
  556.  
  557.   p->bytesfree -= needed; /* decrease # of free bytes in the page */
  558.   p->maxcontigfree = maxcontig;
  559.   f->bytesfree = needed;  /* set the length field 
  560.                              in the returned chunk */
  561.   
  562.   /* Clear the allocated memory to zeroes */
  563.   memset(p->memaddr + offset + sizeof(FREEINFO), 
  564.          '\0', needed-sizeof(FREEINFO));
  565.  
  566.   /* Return offset */
  567.   h = (HANDLE) (((long) p->id) << 16) | 
  568.       (long) (offset + sizeof(FREEINFO));
  569.   return h;
  570. }
  571.  
  572.  
  573. /* Return a pointer to a page with N bytes free */
  574. PAGE *FindNContigBytesFree(needed)
  575.   unsigned needed;      /* # of bytes needed */
  576. {
  577.   PAGE *diskpage = NULL;
  578.   PAGE *p;
  579.   
  580.   /*
  581.      Traverse the page list looking for a page with the needed
  582.      amount of bytes free in one contiguous chunk.
  583.   */
  584.   for (p = PageList;  p;  p = p->next)
  585.   {
  586.     if (p->maxcontigfree >= needed)
  587.     {
  588.       if (p->flags & PAGE_IN_MEM)
  589.       { /* If the page is in memory, then return it immediately */
  590.         return p;
  591.       }
  592.       else if (p->flags & PAGE_ON_DISK)
  593.       { /* If the page is on disk, then mark it as the candidate */
  594.         if (!diskpage) diskpage = p;
  595.       }
  596.     }
  597.   }
  598.   
  599.   /* 
  600.      At this point, we have no memory-based page with  
  601.      n contiguous bytes, and possibly a disk-based page 
  602.      with n contiguous bytes.
  603.   */
  604.  
  605.   if (diskpage)
  606.   {
  607.     SwapinPage(diskpage);
  608.     CompactifyPage(diskpage);
  609.     return diskpage;
  610.   }
  611.   else
  612.   {
  613.  
  614.     /* No disk page had the needed bytes!!! 
  615.        Try to allocate a new page! */
  616.  
  617.     return AllocPage();
  618.   }
  619. }
  620.  
  621.  
  622. CompactifyPage(p)
  623.   PAGE *p;
  624. {
  625.   /* 
  626.      This routine has nothing in it yet.... Maybe one day, 
  627.      we'll add compaction....
  628.   */
  629. }
  630.  
  631.  
  632.  
  633. void MyFree(h)
  634.   HANDLE h;
  635. {
  636.   char *s;
  637.   int  pid;
  638.   PAGE *pg;
  639.   FREEINFO *f, *hFree, *prevf;
  640.   unsigned fOffset, hOffset, prevfOffset;
  641.  
  642.   /* Swap the page in if necessary */
  643.   if ((s = MemDeref(h)) == NULL)
  644.     return;
  645.  
  646.   pid = (int) ((h >> 16) & 0x0000FFFF);
  647.   hOffset = (int) (h & 0x0000FFFF);
  648.   hOffset -= sizeof(FREEINFO);
  649.   for (pg = PageList;  pg && pg->id != pid;  pg = pg->next)  ;
  650.   SET_PAGE_DIRTY(pg);
  651.  
  652.  
  653.   hFree = FREEPTR(pg, hOffset);
  654.  
  655.   pg->bytesfree += hFree->bytesfree;
  656.  
  657.   /* See if we have an empty free list */
  658.   if (pg->freebyte >= pg->pagesize)
  659.   {
  660.     /*
  661.          pg          h
  662.        freebyte---->nextfree--->X
  663.     */
  664.     pg->freebyte = hOffset;
  665.     pg->maxcontigfree = hFree->bytesfree;
  666.     hFree->nextfree = FREELIST_END;
  667.     return;
  668.   }
  669.   
  670.   /* Traverse free chain until we get a free chunk whose address */
  671.   /*  is larger than the address of the chunk about to be freed. */
  672.   for (f = FREEPTR(pg, (fOffset = pg->freebyte));
  673.        hOffset > fOffset && f->nextfree != FREELIST_END;
  674.        prevfOffset=fOffset, prevf=f, 
  675.        f = FREEPTR(pg, (fOffset = f->nextfree)))
  676.     ;
  677.     
  678.   /* See if we should insert the new chunk after the tail */
  679.   /*
  680.        100         200
  681.         f           h
  682.      nextfree--->nextfree--->X
  683.  
  684.   */
  685.   if (hOffset > fOffset) /* we got here cause we hit the end */
  686.   {
  687.     /* Try to combine chunks f and h */
  688.     if (fOffset + f->bytesfree == hOffset)
  689.     {
  690.       f->bytesfree += hFree->bytesfree;
  691.       /* We should examine the block after f for coalescing */
  692.     }
  693.     else        /* Can't combine */
  694.     {
  695.       hFree->nextfree = FREELIST_END;
  696.       f->nextfree = hOffset;
  697.       /* We should examine the block after h for coalescing */
  698. set_f_to_h:
  699.       f = hFree;
  700.       fOffset = hOffset;
  701.       pg->maxcontigfree = max(pg->maxcontigfree, hFree->bytesfree);
  702.     }
  703.   }
  704.   
  705.   /* See if we should insert before the first free chunk */
  706.   else if (pg->freebyte == fOffset)
  707.   {
  708.     /*
  709.          pg->freebyte = 300
  710.  
  711.          200     300
  712.           h------>f
  713.     */
  714.     
  715.     hFree->nextfree = fOffset;
  716.     pg->freebyte = hOffset;
  717.     /* We should examine the block after h for coalescing */
  718.     goto set_f_to_h;
  719.   }
  720.   
  721.   /* We must be inserting between two existing free chunks */
  722.   else
  723.   {
  724.     /*
  725.        100         200        300
  726.       prevf         h          f
  727.      nextfree--->nextfree--->nextfree--->
  728.     */
  729.     /* See if we can coalesce prevf and h */
  730.     if (prevfOffset + prevf->bytesfree == hOffset)
  731.     {
  732.       prevf->bytesfree += hFree->bytesfree;
  733.       /* We should examine the block after prevf for coalescing */
  734.       f = prevf;
  735.       fOffset = prevfOffset;
  736.       pg->maxcontigfree = max(pg->maxcontigfree, prevf->bytesfree);
  737.     }
  738.     else
  739.     {
  740.       hFree->nextfree = prevf->nextfree;
  741.       prevf->nextfree = hOffset;
  742.       /* We should examine the block after h for coalescing */
  743.       goto set_f_to_h;
  744.     }
  745.   }
  746.   
  747.   /* We want to examine the block after 
  748.      chunk f to see if we can coalesce */
  749.  
  750.   if (f->nextfree != FREELIST_END  &&  
  751.                      fOffset + f->bytesfree == f->nextfree)
  752.   {
  753.     hFree = FREEPTR(pg, f->nextfree);
  754.     f->nextfree = hFree->nextfree;
  755.     f->bytesfree += hFree->bytesfree;
  756.     pg->maxcontigfree = max(pg->maxcontigfree, f->bytesfree);
  757.   }
  758. }
  759.  
  760.  
  761.  
  762. char far *mymalloc(size)
  763.   unsigned int size;
  764. {
  765.   char *s;
  766.   unsigned seg;
  767.   unsigned paras;
  768.   
  769.   /* We know that we have no DOS memory left */
  770.   if (Emergency)
  771.     return NULL;
  772.  
  773.   /* Convert bytes to paragraphs */
  774.   paras = (size + 15) >> 4;
  775.  
  776.   /* Let DOS to do the allocation */
  777.   if (_dos_allocmem(paras, &seg) != 0)
  778.   {
  779.     Emergency++;
  780.     return NULL;
  781.   }
  782.  
  783.   /*
  784.     Convert the alocated memory into a far address and clear it out
  785.   */
  786.  
  787.   FP_SEG(s) = seg;
  788.   FP_OFF(s) = 0;
  789.   memset(s, 0, paras << 4);
  790.   return s;
  791. }
  792.  
  793.  
  794. my_free(s)
  795.   char far *s;
  796. {
  797.   /* The memory must be returned to DOS */
  798.   _dos_freemem(FP_SEG(s));
  799.   Emergency = FALSE;    /* we can alloc some more DOS memory */
  800. }
  801.  
  802.  
  803. SetVMPageSize(kbytes)
  804.   int kbytes;
  805. {
  806.   VMPageSize = (unsigned) kbytes * 1024;
  807. }
  808.  
  809.